{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "559f8e0e",
   "metadata": {},
   "source": [
    "# Vectara\n",
    "\n",
    "[Vectara](https://vectara.com/) provides a Trusted Generative AI platform, allowing organizations to rapidly create a ChatGPT-like experience (an AI assistant) which is grounded in the data, documents, and knowledge that they have (technically, it is Retrieval-Augmented-Generation-as-a-service). \n",
    "\n",
    "Vectara serverless RAG-as-a-service provides all the components of RAG behind an easy-to-use API, including:\n",
    "1. A way to extract text from files (PDF, PPT, DOCX, etc)\n",
    "2. ML-based chunking that provides state of the art performance.\n",
    "3. The [Boomerang](https://vectara.com/how-boomerang-takes-retrieval-augmented-generation-to-the-next-level-via-grounded-generation/) embeddings model.\n",
    "4. Its own internal vector database where text chunks and embedding vectors are stored.\n",
    "5. A query service that automatically encodes the query into embedding, and retrieves the most relevant text segments (including support for [Hybrid Search](https://docs.vectara.com/docs/api-reference/search-apis/lexical-matching) and [MMR](https://vectara.com/get-diverse-results-and-comprehensive-summaries-with-vectaras-mmr-reranker/))\n",
    "7. An LLM to for creating a [generative summary](https://docs.vectara.com/docs/learn/grounded-generation/grounded-generation-overview), based on the retrieved documents (context), including citations.\n",
    "\n",
    "See the [Vectara API documentation](https://docs.vectara.com/docs/) for more information on how to use the API.\n",
    "\n",
    "This notebook shows how to use the basic retrieval functionality, when utilizing Vectara just as a Vector Store (without summarization), incuding: `similarity_search` and `similarity_search_with_score` as well as using the LangChain `as_retriever` functionality.\n",
    "\n",
    "You'll need to install `langchain-community` with `pip install -qU langchain-community` to use this integration"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e97dcf11",
   "metadata": {},
   "source": [
    "# Getting Started\n",
    "\n",
    "To get started, use the following steps:\n",
    "1. If you don't already have one, [Sign up](https://www.vectara.com/integrations/langchain) for your free Vectara account. Once you have completed your sign up you will have a Vectara customer ID. You can find your customer ID by clicking on your name, on the top-right of the Vectara console window.\n",
    "2. Within your account you can create one or more corpora. Each corpus represents an area that stores text data upon ingest from input documents. To create a corpus, use the **\"Create Corpus\"** button. You then provide a name to your corpus as well as a description. Optionally you can define filtering attributes and apply some advanced options. If you click on your created corpus, you can see its name and corpus ID right on the top.\n",
    "3. Next you'll need to create API keys to access the corpus. Click on the **\"Access Control\"** tab in the corpus view and then the **\"Create API Key\"** button. Give your key a name, and choose whether you want query-only or query+index for your key. Click \"Create\" and you now have an active API key. Keep this key confidential. \n",
    "\n",
    "To use LangChain with Vectara, you'll need to have these three values: `customer ID`, `corpus ID` and `api_key`.\n",
    "You can provide those to LangChain in two ways:\n",
    "\n",
    "1. Include in your environment these three variables: `VECTARA_CUSTOMER_ID`, `VECTARA_CORPUS_ID` and `VECTARA_API_KEY`.\n",
    "\n",
    "   For example, you can set these variables using os.environ and getpass as follows:\n",
    "\n",
    "```python\n",
    "import os\n",
    "import getpass\n",
    "\n",
    "os.environ[\"VECTARA_CUSTOMER_ID\"] = getpass.getpass(\"Vectara Customer ID:\")\n",
    "os.environ[\"VECTARA_CORPUS_ID\"] = getpass.getpass(\"Vectara Corpus ID:\")\n",
    "os.environ[\"VECTARA_API_KEY\"] = getpass.getpass(\"Vectara API Key:\")\n",
    "```\n",
    "\n",
    "2. Add them to the `Vectara` vectorstore constructor:\n",
    "\n",
    "```python\n",
    "vectara = Vectara(\n",
    "                vectara_customer_id=vectara_customer_id,\n",
    "                vectara_corpus_id=vectara_corpus_id,\n",
    "                vectara_api_key=vectara_api_key\n",
    "            )\n",
    "```\n",
    "\n",
    "In this notebook we assume they are provided in the environment."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "aac7a9a6",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "\n",
    "os.environ[\"VECTARA_API_KEY\"] = \"<YOUR_VECTARA_API_KEY>\"\n",
    "os.environ[\"VECTARA_CORPUS_ID\"] = \"<YOUR_VECTARA_CORPUS_ID>\"\n",
    "os.environ[\"VECTARA_CUSTOMER_ID\"] = \"<YOUR_VECTARA_CUSTOMER_ID>\"\n",
    "\n",
    "from langchain_community.vectorstores import Vectara\n",
    "from langchain_community.vectorstores.vectara import (\n",
    "    RerankConfig,\n",
    "    SummaryConfig,\n",
    "    VectaraQueryConfig,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "875ffb7e",
   "metadata": {},
   "source": [
    "First we load the state-of-the-union text into Vectara. \n",
    "\n",
    "Note that we use the `from_files` interface which does not require any local processing or chunking - Vectara receives the file content and performs all the necessary pre-processing, chunking and embedding of the file into its knowledge store.\n",
    "\n",
    "In this case it uses a `.txt` file but the same works for many other [file types](https://docs.vectara.com/docs/api-reference/indexing-apis/file-upload/file-upload-filetypes)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "be0a4973",
   "metadata": {},
   "outputs": [],
   "source": [
    "vectara = Vectara.from_files([\"state_of_the_union.txt\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "22a6b953",
   "metadata": {},
   "source": [
    "## Basic Vectara RAG (retrieval augmented generation)\n",
    "\n",
    "We now create a `VectaraQueryConfig` object to control the retrieval and summarization options:\n",
    "* We enable summarization, specifying we would like the LLM to pick the top 7 matching chunks and respond in English\n",
    "* We enable MMR (max marginal relevance) in the retrieval process, with a 0.2 diversity bias factor\n",
    "* We want the top-10 results, with hybrid search configured with a value of 0.025\n",
    "\n",
    "Using this configuration, let's create a LangChain `Runnable` object that encpasulates the full Vectara RAG pipeline, using the `as_rag` method:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "9ecda054-96a8-4a91-aeae-32006efb1ac8",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\"Biden addressed various topics in his statements. He highlighted the need to confront Putin by building a coalition of nations[1]. He also expressed commitment to investigating the impact of burn pits on soldiers' health, including his son's case[2]. Additionally, Biden outlined a plan to fight inflation by cutting prescription drug costs[3]. He emphasized the importance of continuing to combat COVID-19 and not just accepting living with it[4]. Furthermore, he discussed measures to weaken Russia economically and target Russian oligarchs[6]. Biden also advocated for passing the Equality Act to support LGBTQ+ Americans and condemned state laws targeting transgender individuals[7].\""
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "summary_config = SummaryConfig(is_enabled=True, max_results=7, response_lang=\"eng\")\n",
    "rerank_config = RerankConfig(reranker=\"mmr\", rerank_k=50, mmr_diversity_bias=0.2)\n",
    "config = VectaraQueryConfig(\n",
    "    k=10, lambda_val=0.005, rerank_config=rerank_config, summary_config=summary_config\n",
    ")\n",
    "\n",
    "query_str = \"what did Biden say?\"\n",
    "\n",
    "rag = vectara.as_rag(config)\n",
    "rag.invoke(query_str)[\"answer\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cd825d63-93a0-4e45-a455-bfabb01ee1a1",
   "metadata": {},
   "source": [
    "We can also use the streaming interface like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "27f01330-8917-4eff-b603-59ab2571a4d2",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Biden addressed various topics in his statements. He highlighted the importance of building coalitions to confront global challenges [1]. He also expressed commitment to investigating the impact of burn pits on soldiers' health, including his son's case [2, 4]. Additionally, Biden outlined his plan to combat inflation by cutting prescription drug costs and reducing the deficit, with support from Nobel laureates and business leaders [3]. He emphasized the ongoing fight against COVID-19 and the need to continue combating the virus [5]. Furthermore, Biden discussed measures taken to weaken Russia's economic and military strength, targeting Russian oligarchs and corrupt leaders [6]. He also advocated for passing the Equality Act to support LGBTQ+ Americans and address discriminatory state laws [7]."
     ]
    }
   ],
   "source": [
    "output = {}\n",
    "curr_key = None\n",
    "for chunk in rag.stream(query_str):\n",
    "    for key in chunk:\n",
    "        if key not in output:\n",
    "            output[key] = chunk[key]\n",
    "        else:\n",
    "            output[key] += chunk[key]\n",
    "        if key == \"answer\":\n",
    "            print(chunk[key], end=\"\", flush=True)\n",
    "        curr_key = key"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7eaf871d-eba2-46b1-bfa3-b9c82947d2be",
   "metadata": {},
   "source": [
    "## Hallucination detection and Factual Consistency Score\n",
    "\n",
    "Vectara created [HHEM](https://huggingface.co/vectara/hallucination_evaluation_model) - an open source model that can be used to evaluate RAG responses for factual consistency. \n",
    "\n",
    "As part of the Vectara RAG, the \"Factual Consistency Score\" (or FCS), which is an improved version of the open source HHEM is made available via the API. This is automatically included in the output of the RAG pipeline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "b2e0aa2c-7c8e-4d79-8abc-66f5a1f961b3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Biden addressed various topics in his statements. He highlighted the need to confront Putin by building a coalition of nations[1]. He also expressed his commitment to investigating the impact of burn pits on soldiers' health, referencing his son's experience[2]. Additionally, Biden discussed his plan to fight inflation by cutting prescription drug costs and garnering support from Nobel laureates and business leaders[4]. Furthermore, he emphasized the importance of continuing to combat COVID-19 and not merely accepting living with the virus[5]. Biden's remarks encompassed international relations, healthcare challenges faced by soldiers, economic strategies, and the ongoing battle against the pandemic.\n",
      "Vectara FCS = 0.41796625\n"
     ]
    }
   ],
   "source": [
    "summary_config = SummaryConfig(is_enabled=True, max_results=5, response_lang=\"eng\")\n",
    "rerank_config = RerankConfig(reranker=\"mmr\", rerank_k=50, mmr_diversity_bias=0.1)\n",
    "config = VectaraQueryConfig(\n",
    "    k=10, lambda_val=0.005, rerank_config=rerank_config, summary_config=summary_config\n",
    ")\n",
    "\n",
    "rag = vectara.as_rag(config)\n",
    "resp = rag.invoke(query_str)\n",
    "print(resp[\"answer\"])\n",
    "print(f\"Vectara FCS = {resp['fcs']}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b651396a-5726-4d49-bacf-c9d7a5ddcf7a",
   "metadata": {},
   "source": [
    "## Vectara as a langchain retreiver\n",
    "\n",
    "The Vectara component can also be used just as a retriever. \n",
    "\n",
    "In this case, it behaves just like any other LangChain retriever. The main use of this mode is for semantic search, and in this case we disable summarization:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "19cd2f86",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Document(page_content='He thought the West and NATO wouldn’t respond. And he thought he could divide us at home. We were ready.  Here is what we did. We prepared extensively and carefully. We spent months building a coalition of other freedom-loving nations from Europe and the Americas to Asia and Africa to confront Putin.', metadata={'lang': 'eng', 'section': '1', 'offset': '2160', 'len': '36', 'X-TIKA:Parsed-By': 'org.apache.tika.parser.csv.TextAndCSVParser', 'Content-Encoding': 'UTF-8', 'Content-Type': 'text/plain; charset=UTF-8', 'source': 'vectara'}),\n",
       " Document(page_content='When they came home, many of the world’s fittest and best trained warriors were never the same. Dizziness. \\n\\nA cancer that would put them in a flag-draped coffin. I know. \\n\\nOne of those soldiers was my son Major Beau Biden. We don’t know for sure if a burn pit was the cause of his brain cancer, or the diseases of so many of our troops. But I’m committed to finding out everything we can.', metadata={'lang': 'eng', 'section': '1', 'offset': '34652', 'len': '60', 'X-TIKA:Parsed-By': 'org.apache.tika.parser.csv.TextAndCSVParser', 'Content-Encoding': 'UTF-8', 'Content-Type': 'text/plain; charset=UTF-8', 'source': 'vectara'}),\n",
       " Document(page_content='But cancer from prolonged exposure to burn pits ravaged Heath’s lungs and body. Danielle says Heath was a fighter to the very end. He didn’t know how to stop fighting, and neither did she. Through her pain she found purpose to demand we do better. Tonight, Danielle—we are.', metadata={'lang': 'eng', 'section': '1', 'offset': '35442', 'len': '57', 'X-TIKA:Parsed-By': 'org.apache.tika.parser.csv.TextAndCSVParser', 'Content-Encoding': 'UTF-8', 'Content-Type': 'text/plain; charset=UTF-8', 'source': 'vectara'})]"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "config.summary_config.is_enabled = False\n",
    "config.k = 3\n",
    "retriever = vectara.as_retriever(config=config)\n",
    "retriever.invoke(query_str)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c49284ed",
   "metadata": {},
   "source": [
    "For backwards compatibility, you can also enable summarization with a retriever, in which case the summary is added as an additional Document object:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "59268e9a-6089-4bb2-8c61-1ea6b956f83c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Document(page_content='He thought the West and NATO wouldn’t respond. And he thought he could divide us at home. We were ready.  Here is what we did. We prepared extensively and carefully. We spent months building a coalition of other freedom-loving nations from Europe and the Americas to Asia and Africa to confront Putin.', metadata={'lang': 'eng', 'section': '1', 'offset': '2160', 'len': '36', 'X-TIKA:Parsed-By': 'org.apache.tika.parser.csv.TextAndCSVParser', 'Content-Encoding': 'UTF-8', 'Content-Type': 'text/plain; charset=UTF-8', 'source': 'vectara'}),\n",
       " Document(page_content='When they came home, many of the world’s fittest and best trained warriors were never the same. Dizziness. \\n\\nA cancer that would put them in a flag-draped coffin. I know. \\n\\nOne of those soldiers was my son Major Beau Biden. We don’t know for sure if a burn pit was the cause of his brain cancer, or the diseases of so many of our troops. But I’m committed to finding out everything we can.', metadata={'lang': 'eng', 'section': '1', 'offset': '34652', 'len': '60', 'X-TIKA:Parsed-By': 'org.apache.tika.parser.csv.TextAndCSVParser', 'Content-Encoding': 'UTF-8', 'Content-Type': 'text/plain; charset=UTF-8', 'source': 'vectara'}),\n",
       " Document(page_content='But cancer from prolonged exposure to burn pits ravaged Heath’s lungs and body. Danielle says Heath was a fighter to the very end. He didn’t know how to stop fighting, and neither did she. Through her pain she found purpose to demand we do better. Tonight, Danielle—we are.', metadata={'lang': 'eng', 'section': '1', 'offset': '35442', 'len': '57', 'X-TIKA:Parsed-By': 'org.apache.tika.parser.csv.TextAndCSVParser', 'Content-Encoding': 'UTF-8', 'Content-Type': 'text/plain; charset=UTF-8', 'source': 'vectara'}),\n",
       " Document(page_content=\"Biden discussed various topics in his statements. He highlighted the importance of unity and preparation to confront challenges, such as building coalitions to address global issues [1]. Additionally, he shared personal stories about the impact of health issues on soldiers, including his son's experience with brain cancer possibly linked to burn pits [2]. Biden also outlined his plans to combat inflation by cutting prescription drug costs and emphasized the ongoing efforts to combat COVID-19, rejecting the idea of merely living with the virus [4, 5]. Overall, Biden's messages revolved around unity, healthcare challenges faced by soldiers, economic plans, and the ongoing fight against COVID-19.\", metadata={'summary': True, 'fcs': 0.54751414})]"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "config.summary_config.is_enabled = True\n",
    "config.k = 3\n",
    "retriever = vectara.as_retriever(config=config)\n",
    "retriever.invoke(query_str)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8f16bf8d",
   "metadata": {},
   "source": [
    "## Advanced LangChain query pre-processing with Vectara\n",
    "\n",
    "Vectara's \"RAG as a service\" does a lot of the heavy lifting in creating question answering or chatbot chains. The integration with LangChain provides the option to use additional capabilities such as query pre-processing  like `SelfQueryRetriever` or `MultiQueryRetriever`. Let's look at an example of using the [MultiQueryRetriever](https://python.langchain.com/docs/modules/data_connection/retrievers/MultiQueryRetriever).\n",
    "\n",
    "Since MQR uses an LLM we have to set that up - here we choose `ChatOpenAI`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "e14325b9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\"Biden's statement highlighted his efforts to unite freedom-loving nations against Putin's aggression, sharing information in advance to counter Russian lies and hold Putin accountable[1]. Additionally, he emphasized his commitment to military families, like Danielle Robinson, and outlined plans for more affordable housing, Pre-K for 3- and 4-year-olds, and ensuring no additional taxes for those earning less than $400,000 a year[2][3]. The statement also touched on the readiness of the West and NATO to respond to Putin's actions, showcasing extensive preparation and coalition-building efforts[4]. Heath Robinson's story, a combat medic who succumbed to cancer from burn pits, was used to illustrate the resilience and fight for better conditions[5].\""
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain.retrievers.multi_query import MultiQueryRetriever\n",
    "from langchain_openai.chat_models import ChatOpenAI\n",
    "\n",
    "llm = ChatOpenAI(temperature=0)\n",
    "mqr = MultiQueryRetriever.from_llm(retriever=retriever, llm=llm)\n",
    "\n",
    "\n",
    "def get_summary(documents):\n",
    "    return documents[-1].page_content\n",
    "\n",
    "\n",
    "(mqr | get_summary).invoke(query_str)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8060a423-b291-4166-8fd7-ba0e01692b51",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
